/**
 * A JavaScript Date util
 *
 * @package js.lang
 * @author: DSONet (dsonet@msn.com)
 * @version $Id: JDate.js 35 2008-03-02 17:01:34Z dsonet $
 */
/**
 * A JavaScript Date util
 *
 */
var JDate ={
	/** 
	 * 毫秒(毫秒级) 
	 * @public
	 * @id JDate.SECOND
	 */
	SECOND : 1000
	/** 
	 * 分钟(毫秒级)
	 * @public
	 * @id JDate.MINUTE
	 */
	, MINUTE : 60000/*60 * , SECOND//*/
	/** 
	 * 小时(毫秒级)
	 * @public
	 * @id JDate.HOUR
	 */
	, HOUR : 3600000/*60 * , MINUTE//*/
	/** 
	 * 天(毫秒级)
	 * @public
	 * @id JDate.DAY
	 */
	, DAY : 86400000/*24 * , HOUR//*/
	/** 
	 * 星期(毫秒级)
	 * @public
	 * @id JDate.WEEK
	 */
	, WEEK : 604800000/*7 * , DAY//*/
	/** 
	 * 月份序列(毫秒级)
	 * @public
	 * @typeof array
	 * @member JDate
	 * @id JDate.MDAY
	 */
	, MDAY : [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
	/** 
	 * 得到给定日期对象中指定月份的天数 
	 * @public
	 * @param {Date} date Date对象
	 * @param {number} month 月份
	 * @return {number} 该月天数值
	 * @id JDate.getMonthDays
	 */
	, getMonthDays : function(date, month)
	{
		if (typeof month == "undefined")
		{
			month = date.getMonth();
		}

		return (month == 1 && JDate.isLeapYear(date)) ? 29 : JDate.MDAY[month];
	}
	/** 
	 * 判断给定年份是否是闰年 
	 * @public
	 * @param {Date|number} date Date对象
	 * @return {boolean} 是闰年则true
	 * @id JDate.isLeapYear
	 */
	, isLeapYear : function(/*Date*/date){
	// summary:
	//	Determines if the year of the dateObject is a leap year
	//
	// description:
	//	Leap years are years with an additional day YYYY-02-29, where the year
	//	number is a multiple of four with the following exception: If a year
	//	is a multiple of 100, then it is only a leap year if it is also a
	//	multiple of 400. For example, 1900 was not a leap year, but 2000 is one.
		var year = (typeof date == "number") ? date : date.getFullYear();
		return !(year % 400) || (!(year % 4) && !!(year % 100)); // Boolean
	}
	/** 
	 * 设定 Date 对象中用本地时间表示的年份值.
	 * @public
	 * @param {Date} date Date对象
	 * @param {number} y 年份
	 * @return {Date} Date对象
	 * @id JDate.setFullYear
	 */
	, setFullYear : function(date, y)
	{
		var _setFullYear = Date.prototype.setFullYear
		, d = new Date(date);
		_setFullYear.call(d, y);

		if (d.getMonth() != date.getMonth())
			date.setDate(28);
		_setFullYear.call(date, y);
		return date;
	}
	/** 
	 * 得到指定Date对象中一年的天数
	 * @public
	 * @param {Date} date Date对象
	 * @return {number} 该年天数
	 * @id JDate.getDayOfYear
	 */
	, getDayOfYear : function(date)
	{
		var now = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0)
		, then = new Date(date.getFullYear(), 0, 0, 0, 0, 0)
		, time = now - then;
		return Math.floor(time / JDate.DAY);
	}
	/** 
	 * 得到指定Date对象中一年的周数
	 * @public
	 * @param {Date} date Date对象
	 * @return {number} 该年周数
	 * @id JDate.getWeekOfYear
	 */
	, getWeekOfYear : function(date)
	{
		var d = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0)
		, DoW = d.getDay();
		d.setDate(d.getDate() - (DoW + 6) % 7 + 3);
		var ms = d.valueOf();
		d.setMonth(0);
		d.setDate(4);
		return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
	}
	/** 
	 * 比较两个日期对象是否相同(精确到分钟)
	 * @public
	 * @param {Date} date1 Date对象
	 * @param {Date} date2 Date对象
	 * @return {boolean} 返回true为相同,false为不同
	 * @id JDate.equals
	 */
	, equals : function(date1, date2)
	{
		return (date1.getFullYear() == date2.getFullYear()) && (date1.getMonth() == date2.getMonth())
			&& (date1.getDate() == date2.getDate()) && (date1.getHours() == date2.getHours())
			&& (date1.getMinutes() == date2.getMinutes());
	}
	/** 
	 * 比较两个日期对象是否相同(仅比较年月日)
	 * @public
	 * @param {Date} date1 Date对象
	 * @param {Date} date2 Date对象
	 * @return {boolean} 返回true为相同,false为不同
	 * @id JDate.dateEquals
	 */
	, dateEquals : function(date1, date2)
	{
		return (date1.getFullYear() == date2.getFullYear()) && (date1.getMonth() == date2.getMonth())
			&& (date1.getDate() == date2.getDate());
	}
	, dateAdd : function(/*Date*/date, /*int*/amount, /*String*/interval){
		//	summary
		//		Add to a Date in intervals of different size, from milliseconds to years
		//
		//	date
		//		Date object to start with
		//
		//	interval
		//		A string representing the interval.  One of the following:
		//			"year", "month", "day", "hour", "minute", "second", "millisecond", "quarter", "week", "weekday"
		//
		//	amount
		//		How much to add to the date.
	
		var sum = new Date(Number(date)) // convert to Number before copying to accomodate IE (#3112)
		, fixOvershoot = false
		, property = "Date";
	
		switch(interval){
			case "day":
			case "d":
				break;
			case "weekday":
				//i18n FIXME: assumes Saturday/Sunday weekend, but even this is not standard.  There are CLDR entries to localize this.
				var dayOfMonth = date.getDate() 
				, days
				, weeks
				, adj = 0
				// Divide the increment time span into weekspans plus leftover days
				// e.g., 8 days is one 5-day weekspan / and two leftover days
				// Can't have zero leftover days, so numbers divisible by 5 get
				// a days value of 5, and the remaining days make up the number of weeks
				, mod = amount % 5;
				if(!mod){
					days = (amount > 0) ? 5 : -5;
					weeks = (amount > 0) ? ((amount - 5) / 5) : ((amount + 5) / 5);
				}else{
					days = mod;
					weeks = parseInt(amount / 5);
				}
				// Get weekday value for orig date param
				var strt = date.getDay();
				// Orig date is Sat / positive incrementer
				// Jump over Sun
				if(strt == 6 && amount > 0){
					adj = 1;
				}else if(strt == 0 && amount < 0){
				// Orig date is Sun / negative incrementer
				// Jump back over Sat
					adj = -1;
				}
				// Get weekday val for the new date
				var trgt = strt + days;
				// New date is on Sat or Sun
				if(trgt == 0 || trgt == 6){
					adj = (amount > 0) ? 2 : -2;
				}
				// Increment by number of weeks plus leftover days plus
				// weekend adjustments
				amount = dayOfMonth + 7 * weeks + days + adj;
				break;
			case "year":
				property = "FullYear";
				// Keep increment/decrement from 2/29 out of March
				fixOvershoot = true;
				break;
			case "week":
				amount *= 7;
				break;
			case "quarter":
				// Naive quarter is just three months
				amount *= 3;
				// fallthrough...
			case "month":
				// Reset to last day of month if you overshoot
				fixOvershoot = true;
				property = "Month";
				break;
			case "hour":
			case "minute":
			case "second":
			case "millisecond":
				property = interval.charAt(0).toUpperCase() + interval.substring(1) + "s";
		}
	
		if(property){
			sum["set"+property](sum["get"+property]()+amount);
		}
	
		if(fixOvershoot && (sum.getDate() < date.getDate())){
			sum.setDate(0);
		}
	
		return sum; // Date
	}
	/** 
	 * 返回两个日期之间的时间间隔
	 * @public
	 * @param {Date} date Date对象
	 * @param {Date} cDate Date对象
	 * @param {string} [mode] 表示用于计算 date1 和 date2 之间的时间间隔.可取值为yyyy年,n月,ww周,默认为天
	 * @return {number} 间隔数值
	 * @id JDate.dateDiff
	 */
	, dateDiff : function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){
		//	summary
		//		Get the difference in a specific unit of time (e.g., number of months, weeks,
		//		days, etc.) between two dates, rounded to the nearest integer.
		//
		//	date1
		//		Date object
		//
		//	date2
		//		Date object.  If not specified, the current Date is used.
		//
		//	interval
		//		A string representing the interval.  One of the following:
		//			"year", "month", "day", "hour", "minute", "second", "millisecond", "quarter", "week", "weekday"
		//		Defaults to "day".
	
		date2 = date2 || new Date();
		interval = interval || "day";
		var yearDiff = date2.getFullYear() - date1.getFullYear();
		var delta = 1; // Integer return value
	
		switch(interval){
			case "quarter":
				var m1 = date1.getMonth();
				var m2 = date2.getMonth();
				// Figure out which quarter the months are in
				var q1 = Math.floor(m1/3) + 1;
				var q2 = Math.floor(m2/3) + 1;
				// Add quarters for any year difference between the dates
				q2 += (yearDiff * 4);
				delta = q2 - q1;
				break;
			case "weekday":
				var days = Math.round(JDate.dateDiff(date1, date2, "day"));
				var weeks = parseInt(JDate.dateDiff(date1, date2, "week"));
				var mod = days % 7;
	
				// Even number of weeks
				if(mod == 0){
					days = weeks*5;
				}else{
					// Weeks plus spare change (< 7 days)
					var adj = 0;
					var aDay = date1.getDay();
					var bDay = date2.getDay();
	
					weeks = parseInt(days/7);
					mod = days % 7;
					// Mark the date advanced by the number of
					// round weeks (may be zero)
					var dtMark = new Date(date1);
					dtMark.setDate(dtMark.getDate()+(weeks*7));
					var dayMark = dtMark.getDay();
	
					// Spare change days -- 6 or less
					if(days > 0){
						switch(true){
							// Range starts on Sat
							case aDay == 6:
								adj = -1;
								break;
							// Range starts on Sun
							case aDay == 0:
								adj = 0;
								break;
							// Range ends on Sat
							case bDay == 6:
								adj = -1;
								break;
							// Range ends on Sun
							case bDay == 0:
								adj = -2;
								break;
							// Range contains weekend
							case (dayMark + mod) > 5:
								adj = -2;
						}
					}else if(days < 0){
						switch(true){
							// Range starts on Sat
							case aDay == 6:
								adj = 0;
								break;
							// Range starts on Sun
							case aDay == 0:
								adj = 1;
								break;
							// Range ends on Sat
							case bDay == 6:
								adj = 2;
								break;
							// Range ends on Sun
							case bDay == 0:
								adj = 1;
								break;
							// Range contains weekend
							case (dayMark + mod) < 0:
								adj = 2;
						}
					}
					days += adj;
					days -= (weeks*2);
				}
				delta = days;
				break;
			case "year":
				delta = yearDiff;
				break;
			case "month":
				delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
				break;
			case "week":
				// Truncate instead of rounding
				// Don't use Math.floor -- value may be negative
				delta = parseInt(JDate.dateDiff(date1, date2, "day")/7);
				break;
			case "day":
				delta /= 24;
				// fallthrough
			case "hour":
				delta /= 60;
				// fallthrough
			case "minute":
				delta /= 60;
				// fallthrough
			case "second":
				delta /= 1000;
				// fallthrough
			case "millisecond":
				delta *= date2.getTime() - date1.getTime();
		}
		// Round for fractional values and DST leaps
		return Math.round(delta); // Number (integer)
	}
};